﻿using System;
using System.Collections.ObjectModel;
using System.Messaging;

namespace Hyldahl.Services.TaskProcessing.Data
{
    public class MessageQueueDataProvider : TaskDataProvider
    {
        /*****************************************************
         * DATA METHODS
         *****************************************************/

        /// <summary>
        /// Creates the task.
        /// </summary>
        /// <param name="task">The task.</param>
        public override void CreateTask(Task task)
        {
            ValidateTaskForCreation(task);

            using (MessageQueue queue = new MessageQueue(this.ConnectionString, QueueAccessMode.Send))
            {
                queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(Task) });

                Message message = new Message();

                message.Formatter = new XmlMessageFormatter(new Type[] { typeof(Task) });
                message.Label = task.TaskType;
                message.Body  = task;

                queue.Send(message);
                //queue.Send(task, task.TaskType);
            }
        }

        /// <summary>
        /// Saves the task result.
        /// </summary>
        /// <param name="task">The task.</param>
        public override void SaveTaskResult(Task task)
        {
            if (task == null)
                throw new ArgumentNullException("task");

            if (!task.IsProcessed)
                throw new ArgumentException("Task has not been processed.", "task");

            if (task.Id == Guid.Empty)
                throw new ArgumentException("Invalid task id.", "task");

            if(!task.ProcessingTime.HasValue || task.ProcessingTime < 0)
                throw new ArgumentException("Invalid processing time.", "task");

            if (!task.CompletedSuccessfully.HasValue)
                throw new ArgumentException("Invalid CompletedSuccessfully value.", "task");

            if (!task.CompletedDate.HasValue)
                throw new ArgumentException("Invalid CompletedDate value.", "task");

            // Throw away task result
        }

        /// <summary>
        /// Gets the tasks.
        /// </summary>
        /// <returns></returns>
        public override Collection<Task> GetTasks()
        {
            using (MessageQueue queue = new MessageQueue(this.ConnectionString, QueueAccessMode.Peek))
            {
                queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(Task) });

                Message[] msgs = queue.GetAllMessages();

                Collection<Task> taskList = new Collection<Task>();

                foreach (Message msg in msgs)
                {
                    taskList.Add((Task)msg.Body);
                }

                return taskList;
            }
        }

        /// <summary>
        /// Gets the task.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public override Task GetTask(Guid id)
        {
            using (MessageQueue queue = new MessageQueue(this.ConnectionString, QueueAccessMode.Peek))
            {
                queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(Task) });

                Message msg = queue.PeekById(id.ToString());

                if (msg == null)
                    return null;

                return (Task)msg.Body;
            }
        }

        /// <summary>
        /// Gets the an unprocessed task.
        /// </summary>
        /// <returns></returns>
        public override Task GetUnProcessedTask()
        {
            try
            {
                using (MessageQueue queue = new MessageQueue(this.ConnectionString, QueueAccessMode.Receive))
                {
                    queue.Formatter = new XmlMessageFormatter(new Type[] {typeof (Task)});

                    Message msg = queue.Receive(new TimeSpan(0, 0, 0, 0, 500));

                    if (msg == null)
                        return null;

                    return (Task) msg.Body;
                }
            }
            catch(MessageQueueException ex)
            {
                if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
                    return null;
                else
                    throw;
            }
        }
    }
}
